package sg.edu.nus.iss.jass.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;

import sg.edu.nus.iss.jass.model.CompanyDTO;
import sg.edu.nus.iss.jass.model.JobAdvertDTO;
import sg.edu.nus.iss.jass.model.SkillDTO;

/**
 * @version 1.0
 * @author SE19 Team 1
 * 
 */
public class SearchJobAdvertPanel extends JPanel{
	private static final long serialVersionUID = 1L;
	
	public static final String BTN_VIEW_JOBADVERT = "btnViewJobAdvert";
	public static final String BTN_SEARCH_JOBADVERT = "btnSearchJobAdvert";
	
	private Properties properties;
	private int numRows = 0;
	private List<CompanyDTO> companies;
	private List<SkillDTO> skills;
	
	private JButton btnSearchJobAdvert;
	private JButton btnViewJobAdvert;
	private JTextField txtKeywords, txtMinSalary, txtMaxSalary, txtMinStartDate, txtMaxStartDate, txtLoc, txtMinCreateDate, txtMaxCreateDate;
	private JComboBox cbCompanies;
	private DateFormat df = new SimpleDateFormat("dd/MM/yyyy");

	private DefaultTableModel skillTableModel = new DefaultTableModel() {
		private static final long serialVersionUID = 1L;
		
		public boolean isCellEditable(int row, int column) {
			boolean isEditable = false;
			if(column == 0 || column == 3)
				isEditable = true;
			
			return isEditable;
		}
		
		public Class<?> getColumnClass(int columnIndex) {
			if (columnIndex == 0)
				return Boolean.class;
			else
				return super.getColumnClass(columnIndex);
		}
	};
	private JTable skillTable = new JTable(skillTableModel);
	
	private JPanel resultPanel;
	private DefaultTableModel defaultTableModel = new DefaultTableModel() {
		private static final long serialVersionUID = 1L;
		
		public boolean isCellEditable(int row, int column) {
			return false;
		}
	};
	private JTable resultTable = new JTable(defaultTableModel);
	
	public SearchJobAdvertPanel(List<SkillDTO> skills, List<CompanyDTO> companies) {
		this.setOpaque(false);
		this.companies = companies;
		this.skills = skills;
		
		loadConfiguration();
		
		resultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		this.setLayout(new BorderLayout());
		this.add(getHeaderPanel(), BorderLayout.NORTH);
		this.add(getSearchPanel(), BorderLayout.CENTER);
		
		resultPanel = new JPanel();
		resultPanel.setOpaque(false);
		this.add(resultPanel, BorderLayout.SOUTH);
		btnViewJobAdvert = new JButton(properties.getProperty("button.label.viewJobAdvert"));
	}
	
	public void addComponentActionListener(ActionListener listener) {
		btnSearchJobAdvert.addActionListener(listener);
		btnViewJobAdvert.addActionListener(listener);
	}
	
	private void loadConfiguration() {
		try {
			properties = new Properties();
			FileInputStream in = new FileInputStream("properties/application.properties");
			properties.load(in);
			in.close();
		}
		catch(Exception ex) {
			ex.printStackTrace();
		}
	}
	
	public JPanel getHeaderPanel(){
		JPanel headerPanel = new JPanel();
		headerPanel.setLayout(new GridLayout(0, 1, 10, 10));
		headerPanel.setOpaque(false);
		
		JLabel msgLabel = new JLabel(properties.getProperty("title.jobadvert.searchJobAdvert"));
		msgLabel.setFont(new Font("Calibri", Font.PLAIN, 30));
		msgLabel.setHorizontalAlignment(SwingConstants.CENTER);
		headerPanel.add(msgLabel);
		
		ImageIcon imgDivider = new ImageIcon("./images/divider.jpg");
		JLabel lblDivider = new JLabel(imgDivider);
		headerPanel.add(lblDivider);
		
		return headerPanel;
	}
	
	public JPanel getSearchPanel(){
		JPanel searchPanel = new JPanel();
		GridBagLayout layout = new GridBagLayout();
		searchPanel.setLayout(layout);
		searchPanel.setOpaque(false);
		
		JLabel label;
		
		label = createLabel(properties.getProperty("label.search.keywords"));
		txtKeywords = createTextField(40);
		addRow(searchPanel, label, txtKeywords, new Insets(3, 5, 3, 5));

		label = createLabel(properties.getProperty("label.jobadvert.skill"));
		skillTable = constructSkillTable();
		addRow(searchPanel, label, new JScrollPane(skillTable), new Insets(3, 5, 3, 5));
		
		label = new JLabel("*** Please kindly select the proficiency level for the skill in order to get an exact match.");
		label.setFont(new Font("Calibri", Font.PLAIN, 12));
		label.setHorizontalAlignment(JLabel.LEFT);
		label.setVerticalAlignment(JLabel.TOP);
		label.setForeground(Color.RED);
		addRow(searchPanel, null, label, new Insets(0, 5, 0, 0));
		
		label = createLabel(properties.getProperty("label.jobadvert.location"));
		txtLoc = createTextField(40);
		addRow(searchPanel, label, txtLoc, new Insets(3, 5, 3, 5));
		
		label = createLabel(properties.getProperty("label.jobadvert.company"));
		cbCompanies = constructCompanyMenu();
		addRow(searchPanel, label, cbCompanies, new Insets(3, 5, 3, 5));
		
		label = createLabel(properties.getProperty("label.jobadvert.salaryRange"));
		JPanel salaryPanel = constructSalaryPanel();
		addRow(searchPanel, label, salaryPanel, new Insets(3, 5, 3, 5));

		label = createLabel(properties.getProperty("label.jobadvert.startDate"));
		JPanel startDatePanel = constructStartDatePanel();
		addRow(searchPanel, label, startDatePanel, new Insets(3, 5, 3, 5));

		label = createLabel(properties.getProperty("label.search.createDate"));
		JPanel createDatePanel = constructCreateDatePanel();
		addRow(searchPanel, label, createDatePanel, new Insets(3, 5, 3, 5));
		
		GridBagConstraints constraints3 = new GridBagConstraints();
		constraints3.insets = new Insets(5, 5, 5, 5);
		constraints3.gridwidth = 4;
		constraints3.gridy = 8;
		constraints3.anchor = GridBagConstraints.CENTER;
		btnSearchJobAdvert = new JButton(properties.getProperty("button.label.searchJobAdvert"));
		btnSearchJobAdvert.setName(BTN_SEARCH_JOBADVERT);
		btnSearchJobAdvert.setFont(new Font("Calibri", Font.BOLD, 16));
		btnSearchJobAdvert.setPreferredSize(new Dimension(250, 25));
		searchPanel.add(btnSearchJobAdvert, constraints3);
		return searchPanel;
	}
	
	private void addRow(JPanel panel, Component label, Component component, Insets insets) {
		GridBagConstraints constraints = new GridBagConstraints();
		constraints.insets = insets;
		constraints.fill = GridBagConstraints.HORIZONTAL;
		
		if(label != null) {
			constraints.gridx = 0;
			constraints.gridy = numRows;
			panel.add(label, constraints);
		}
		
		if(component != null) {
			constraints.gridx = 1;
			constraints.gridy = numRows;
			panel.add(component, constraints);
		}
		numRows++;
	}
	
	private JLabel createLabel(String label) {
		JLabel jlabel = new JLabel(label);
		jlabel.setFont(new Font("Calibri", Font.BOLD, 16));
		jlabel.setHorizontalAlignment(JLabel.RIGHT);
		jlabel.setVerticalAlignment(JLabel.TOP);
		
		return jlabel;
	}
	
	private JTextField createTextField(int fieldSize) {
		JTextField textfield = new JTextField(fieldSize);
		textfield.setFont(new Font("Calibri", Font.PLAIN, 16));
		return textfield;
	}
	
	private JComboBox constructCompanyMenu() {
		String[] companiesMenu = new String[companies.size() + 1];
		
		companiesMenu[0] = "";
		for(int n = 0; n < companies.size(); n++) {
			CompanyDTO companyDTO = companies.get(n);
			if(!companyDTO.getIsAnonymous().booleanValue())
				companiesMenu[n+1] = companyDTO.getName();
			else
				companiesMenu[n+1] = companyDTO.getAlternativeDesc();
		}
		
		cbCompanies = new JComboBox(companiesMenu);
		cbCompanies.setPreferredSize(new Dimension(480,20));
		return cbCompanies;
	}
	
	private JTable constructSkillTable() {
		String[] columnNames = new String[4];
		columnNames[0] = "";
		columnNames[1] = properties.getProperty("table.column.skillDesc");
		columnNames[2] = properties.getProperty("table.column.type");
		columnNames[3] = properties.getProperty("table.column.proficiency");
		
		Object[][] data = new Object[skills.size()][4];
		for(int n = 0; n < skills.size(); n++) {
			SkillDTO skillDTO = skills.get(n);
			
			data[n][0] = new Boolean(false);
			data[n][1] = skillDTO.getDescription();
			data[n][2] = skillDTO.getType();
			data[n][3] = properties.getProperty("option.proficiency.beginner");
		}
		
		skillTableModel.setDataVector(data, columnNames);
		skillTable.setModel(skillTableModel);
		
		//Set Table Columns widths Begin
		JCheckBox checkbox = new JCheckBox();
		TableColumn col = skillTable.getColumnModel().getColumn(0);
		col.setCellEditor(new DefaultCellEditor(checkbox));
	    col.setPreferredWidth(10);
	    
	    col = skillTable.getColumnModel().getColumn(1);
	    col.setPreferredWidth(200);
	    col = skillTable.getColumnModel().getColumn(2);
	    col.setPreferredWidth(80);
	    
	    col = skillTable.getColumnModel().getColumn(3);
	    JComboBox comboBox = new JComboBox();
	    comboBox.addItem(properties.getProperty("option.proficiency.beginner"));
	    comboBox.addItem(properties.getProperty("option.proficiency.intermediate"));
	    comboBox.addItem(properties.getProperty("option.proficiency.expert"));
	    col.setCellEditor(new DefaultCellEditor(comboBox));
	    
	  	//Set Table Columns widths Begin
	    skillTable.setPreferredScrollableViewportSize(new Dimension(470,80));
	    skillTable.setFont(new Font("Calibri", Font.PLAIN, 12));
	    skillTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
	    
	    return skillTable;
	}
	
	private JPanel constructSalaryPanel() {
		JPanel panel = new JPanel();
		
		JLabel lblFrom = createLabel("From $");
		JLabel lblTo = createLabel(" To $");
		txtMinSalary = createTextField(20);
		txtMaxSalary = createTextField(20);
		panel.add(lblFrom);
		panel.add(txtMinSalary);
		panel.add(lblTo);
		panel.add(txtMaxSalary);
		
		return panel;
	}

	private JPanel constructCreateDatePanel() {
		JPanel panel = new JPanel();
		
		JLabel lblFrom = createLabel("Between");
		JLabel lblTo = createLabel(" and ");
		txtMinCreateDate = createTextField(20);
		txtMaxCreateDate = createTextField(20);
		panel.add(lblFrom);
		panel.add(txtMinCreateDate);
		panel.add(lblTo);
		panel.add(txtMaxCreateDate);
		
		return panel;
	}
	
	private JPanel constructStartDatePanel() {
		JPanel panel = new JPanel();
		
		JLabel lblFrom = createLabel("Between");
		JLabel lblTo = createLabel(" and ");
		txtMinStartDate = createTextField(20);
		txtMaxStartDate = createTextField(20);
		panel.add(lblFrom);
		panel.add(txtMinStartDate);
		panel.add(lblTo);
		panel.add(txtMaxStartDate);
		
		return panel;
	}
	
	public void displayResultPanel(List<JobAdvertDTO> matchedJobAdverts){
		String[] columnNames = {"No", "Job Title", "Location", "SalaryRange", "JobAdvertDTO"};
		
		Object[][] data = new Object[matchedJobAdverts.size()][5];
		for(int n = 0; n < matchedJobAdverts.size(); n++) {
			JobAdvertDTO jobAdvertDTO = matchedJobAdverts.get(n);
			
			data[n][0] = String.valueOf(n+1);
			data[n][1] = jobAdvertDTO.getJobTitle();
			data[n][2] = jobAdvertDTO.getLocation();
			data[n][3] = jobAdvertDTO.getSalaryRange();
			data[n][4] = jobAdvertDTO;
		}
		
		defaultTableModel.setDataVector(data, columnNames);
		resultTable.setModel(defaultTableModel);
		resultTable.removeColumn(resultTable.getColumnModel().getColumn(4)); // Not to display to Column.
		resultTable.setPreferredScrollableViewportSize(new Dimension(900,150));
		
		JPanel searchResultPanel = new JPanel();
		searchResultPanel.setOpaque(false);
		searchResultPanel.setLayout(new BorderLayout());
		searchResultPanel.add(new JScrollPane(resultTable), BorderLayout.NORTH);
		
		resultPanel.removeAll();
		resultPanel.add(searchResultPanel);
		resultPanel.getRootPane().revalidate();
		
		JPanel buttonPanel = new JPanel();
		buttonPanel.setOpaque(false);
		buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		
		
		btnViewJobAdvert.setName(BTN_VIEW_JOBADVERT);
		btnViewJobAdvert.setPreferredSize(new Dimension(250, 25));
		btnViewJobAdvert.setFont(new Font("Calibri", Font.BOLD, 16));
		buttonPanel.add(btnViewJobAdvert);
		searchResultPanel.add(buttonPanel, BorderLayout.SOUTH);
		
	}

	public void clearResultPanel() {
		resultPanel.removeAll();
		resultPanel.getRootPane().revalidate();
	}
	
	public JTable getResultTable() {
		return resultTable;
	}

	public void setResultTable(JTable resultTable) {
		this.resultTable = resultTable;
	}
	
	public HashMap<String, Object> getFormData(){
		String errorMsg = "";
		HashMap<String, Object> searchCriteria = new HashMap<String, Object>();
		
		//Keywords
		if(txtKeywords.getText().trim().length() != 0) {
			searchCriteria.put("Keywords", txtKeywords.getText().trim());
		}
		
		//Skills
		List<SkillDTO> selectedSkills = new ArrayList<SkillDTO>();
		for(int n = 0; n < skillTableModel.getRowCount(); n++) {
			Boolean tempSelection = (Boolean)skillTableModel.getValueAt(n, 0);
			if(tempSelection.booleanValue()) {
				SkillDTO selectedSkillDTO = skills.get(n);
				selectedSkillDTO.setProficiencyLevel((String)skillTableModel.getValueAt(n, 3));
				selectedSkills.add(selectedSkillDTO);
			}
		}
		if(selectedSkills.size() != 0) {
			searchCriteria.put("Skills", selectedSkills);
		}
		
		//Location
		if(txtLoc.getText().trim().length() != 0) {
			searchCriteria.put("Location", txtLoc.getText().trim());
		}
		
		//Company
		if(cbCompanies.getSelectedIndex() != 0) {
			searchCriteria.put("Company", companies.get(cbCompanies.getSelectedIndex()-1).getId());
		}
		
		//Salary Range
		try {
			if(txtMinSalary.getText().trim().length() != 0) {
				searchCriteria.put("MinSalary", txtMinSalary.getText().trim());
				Integer.parseInt(txtMinSalary.getText().trim());
			}
			if(txtMaxSalary.getText().trim().length() != 0) {
				searchCriteria.put("MaxSalary", txtMaxSalary.getText().trim());
				Integer.parseInt(txtMaxSalary.getText().trim());
			}
		}
		catch(NumberFormatException ex) {
			errorMsg += properties.getProperty("error.jobAdvert.salaryRangeNonNumeric");
		}
		
		//Start Date
		try {
			if(txtMinStartDate.getText().trim().length() != 0) {
				searchCriteria.put("MinStartDate", txtMinStartDate.getText().trim());
				df.parse(txtMinStartDate.getText().trim());
			}
			if(txtMaxStartDate.getText().trim().length() != 0) {
				searchCriteria.put("MaxStartDate", txtMaxStartDate.getText().trim());
				df.parse(txtMaxStartDate.getText().trim());
			}
		}
		catch(Exception ex) {
			errorMsg += properties.getProperty("error.jobAdvert.startDtUnknownFormat");
		}
		
		//Create Date
		try {
			if(txtMinCreateDate.getText().trim().length() != 0) {
				searchCriteria.put("MinCreateDate", txtMinCreateDate.getText().trim());
				df.parse(txtMinCreateDate.getText().trim());
			}
			if(txtMaxCreateDate.getText().trim().length() != 0) {
				searchCriteria.put("MaxCreateDate", txtMaxCreateDate.getText().trim());
				df.parse(txtMaxCreateDate.getText().trim());
			}
		}
		catch(Exception ex) {
			errorMsg += properties.getProperty("error.jobAdvert.creationDtUnknownFormat");
		}
		
		if(errorMsg.length() > 0) {
			String displayMsg = properties.getProperty("error.jobAdvert.searchUnsuccessful.main");
			displayError(displayMsg + errorMsg);
			return null;
		}
		else {
			if(!validate(searchCriteria)) {
				errorMsg = properties.getProperty("error.jobAdvert.noSearchCriteria");
				displayError(errorMsg);
				return null;
			}
		}
		
		return searchCriteria;
	}
	
	private boolean validate(HashMap<String, Object> searchCriteria){
		if(searchCriteria.size() == 0){
			return false;
		} else {
			return true;
		}
	}
	
	public String getSelectedJobAdvertId() {
		String id = null;
		int selectedRow = getResultTable().getSelectedRow();
		
		if(selectedRow > -1){
			JobAdvertDTO selectedJobAdvertDTO = (JobAdvertDTO)getResultTable().getModel().getValueAt(selectedRow, 4);
			id = selectedJobAdvertDTO.getId();
		}
		return id;
	}
	
	public void displayNoResultError(){
		String errorMsg = properties.getProperty("error.jobAdvert.noSearchResult");
		displayError(errorMsg);
		clearResultPanel();
	}
	
	private void displayError(String errorMsg) {
		JOptionPane.showMessageDialog(this, errorMsg, properties.getProperty("mainMenu.label.searchJobAdvert"), JOptionPane.INFORMATION_MESSAGE);
	}
}

